#Required libraries

library(tidyr)
library(tidyverse)
library(ggplot2)
library(ggpubr)

#Reading metadata and presence/absence matrix

mutans_metadata <- read.csv(file = "../Data/Metadata_pangenome_analysis.csv")

PA_matrix_true <- read.delim(file = "../Data/roary_95_ancientAssemblies_gene_presence_absence.Rtab")

PA_matrix_true_t <- PA_matrix_true[,-1]
rownames(PA_matrix_true_t) <- PA_matrix_true[,1]
PA_matrix_true_t <- t(PA_matrix_true_t)

PA_matrix <- read.delim(file = "../Data/roary_95_ancientAssemblies_gene_presence_absence.Rtab") %>%
  gather(Genome, Condition, 2:ncol(PA_matrix_true)) %>%
  filter(Condition != "0")

#Basic statistics

geneGenome <- PA_matrix %>%
  group_by(Genome) %>%
  summarise(Genes=n())

geneCount <- PA_matrix %>%
  left_join(mutans_metadata, by = c("Genome" = "Assembly")) %>%
  group_by(Gene) %>%
  summarise(Total = sum(Condition)) %>%
  mutate(GeneType =
           case_when(
             Total > (492*0.95) ~ "Core genes",
             Total < (492*0.15) ~ "Cloud genes",
             .default = "Shell genes"
           )
         )

geneCountSpecies <- PA_matrix %>%
  left_join(mutans_metadata, by = c("Genome" = "Assembly")) %>%
  group_by(Gene,Age) %>%
  summarise(Total = sum(Condition)) %>%
  mutate(GeneType =
           case_when(
             Total >= 33 & Age == "Ancient" ~ "Core genes",
             Total > (456*0.95) & Age == "Modern" ~ "Core genes", 
             Total < (35*0.15) & Age == "Ancient" ~ "Cloud genes",
             Total < (456*0.15) & Age == "Modern" ~ "Cloud genes",
             .default = "Shell genes"
           )
         )

geneCountSpecies_90complete <- PA_matrix %>%
  left_join(mutans_metadata, by = c("Genome" = "Assembly")) %>%
  filter(Completeness >=90 | is.na(Completeness)) %>%
  group_by(Gene,Age) %>%
  summarise(Total = sum(Condition)) %>%
  mutate(GeneType =
           case_when(
             Total >= 29 & Age == "Ancient" ~ "Core genes",
             Total > (456*0.95) & Age == "Modern" ~ "Core genes", 
             Total < (31*0.15) & Age == "Ancient" ~ "Cloud genes",
             Total < (456*0.15) & Age == "Modern" ~ "Cloud genes",
             .default = "Shell genes"
           )
         )

genePresent5Percent <- PA_matrix %>%
  group_by(Gene) %>%
  summarise(Total = sum(Condition))  %>%
  mutate(Percentage = Total/491*100) %>%
  filter(Percentage >= 15)
  
geneCountSpecies %>%
  group_by(Age,GeneType) %>%
  summarise(GeneTotal = n()) %>%
ggplot(aes(x=GeneType, y=GeneTotal, fill = Age)) +
  geom_bar(position= "dodge", stat="identity") +
  labs(color = "Age", x = "Age", y = "Total gene count/genome") +
  theme_bw() +
  theme(axis.text.x = element_text(angle=45,hjust=1), 
        legend.position="right")


geneCountSpecies_90complete %>%
  group_by(Age,GeneType) %>%
  summarise(GeneTotal = n()) %>%
ggplot(aes(x=GeneType, y=GeneTotal, fill = Age)) +
  geom_bar(position= "dodge", stat="identity") +
  labs(color = "Age", x = "Age", y = "Total gene count/genome") +
  theme_bw() +
  theme(axis.text.x = element_text(angle=45,hjust=1), 
        legend.position="right")


coreGenesAll <- geneCount %>% filter(GeneType == "Core genes")
coreGenesShared <- geneCountSpecies %>% filter(GeneType == "Core genes") %>% group_by(Gene) %>% summarise(total = n()) %>% filter(total == 2) %>% filter(Gene %in% coreGenesAll$Gene)
nonCoreAncient <- geneCountSpecies_90complete %>% filter(Age == "Ancient") %>% filter(Gene %in% coreGenesAll$Gene) %>% filter(!Gene %in% coreGenesShared$Gene)

Probes_coverage

#Reading mapping coverage (breadth and depth) ancient genomes

ancient_genomes_assembly <- mutans_metadata %>% 
  filter(Age == "Ancient")
ancientGenomes_5X <- read.delim("../Data/metadata_ancient_genomes_coverage.csv", sep = ",")
depth_coverage_ancient <- read_delim(file = "../Data/pangenome_mutans.depth.bed", col_names = c("Genome_ancient","Gene_roary","start","end","depth"))

breadth_coverage_ancient <- read_delim(file = "../Data/pangenome_mutans.breadth.bed", col_names = c("Genome_ancient","Gene_roary","breadth"))

depth_breadth_coverage_ancient <- depth_coverage_ancient %>% left_join(breadth_coverage_ancient) %>%
  left_join(gene_presence_absence_csv)

ancient_breadth_depth_cov <- depth_breadth_coverage_ancient %>%
  filter(Genome_ancient %in% ancientGenomes_5X$Genome) %>%
  left_join(ancientGenomes_5X) %>%
  mutate(depth_corrected = depth/Mean_coverage,
         Expected_coverage = (1-exp(-0.883*Mean_coverage)))

ancient_breadth_depth_cov_filtered <- ancient_breadth_depth_cov %>% 
  mutate(Condition = case_when(breadth >= Depth_cov_1X/100 & depth_corrected >= 0.5 & depth_corrected < 1.25 ~ 1, .default = 0)#,
         #Condition2 = case_when(breadth >= Expected_coverage & depth_corrected >= 0.5 & depth_corrected < 1.25 ~ 1, .default = 0)
         )

PA_matrix_anc_mapped <- ancient_breadth_depth_cov_filtered %>% 
  filter(Condition != 0) %>%
  select(Gene, Genome_ancient, Condition) %>%
  rename(Genome = Genome_ancient, 
         #Condition = Condition2
         ) %>%
  rbind(PA_matrix)

map_assem_code <- read.delim("../Data/strain_assembly.csv", sep = ",")

PA_matrix_only_ancient <- PA_matrix_anc_mapped %>% 
  filter(grepl("SM1|MEGAHIT|KGH2|PAN0",Genome)) %>%
  left_join(map_assem_code) %>%
  left_join(ancientGenomes_5X, by = c("Strain"="Genome_ancient"))

geneCountMapping <- PA_matrix_only_ancient %>%
  filter(!is.na(Assembly_name)) %>%
  group_by(Genome) %>%
  summarise(geneCount = sum(Condition)) %>%
  left_join(map_assem_code) %>%
#  left_join(geneGenome) %>%
  left_join(ancientGenomes_5X, by = c("Strain"="Genome_ancient"))

geneCountMappingAssembled <-PA_matrix_only_ancient %>%
  filter(!is.na(Assembly_name)) %>%
  group_by(Genome) %>%
  summarise(geneCount = sum(Condition)) %>%
  left_join(map_assem_code) %>%
  left_join(ancientGenomes_5X, by = c("Strain"="Genome_ancient")) %>%
  filter(Assembly_name != "")

geneCountStrain <- PA_matrix_only_ancient %>%
  filter(!is.na(Assembly_name)) %>%
  group_by(Strain, Gene) %>%
  summarise(geneCountTotal = sum(Condition)) %>%
  mutate(geneCountCorrected = 1) %>%
  group_by(Strain) %>%
  summarise(geneCount = sum(geneCountCorrected)) %>%
  mutate(Type = "Merged") %>%
  left_join(ancientGenomes_5X, by = c("Strain"="Genome_ancient")) %>%
  select(Strain, geneCount, Type, Strain_mixture)

geneCountStrainAssembled <- PA_matrix_only_ancient %>%
  filter(!is.na(Assembly_name)) %>%
  group_by(Strain, Gene) %>%
  summarise(geneCountTotal = sum(Condition)) %>%
  mutate(geneCountCorrected = 1) %>%
  group_by(Strain) %>%
  summarise(geneCount = sum(geneCountCorrected)) %>%
  mutate(Type = "Ancient Merged") %>%
  left_join(ancientGenomes_5X, by = c("Strain"="Genome_ancient")) %>%
  filter(Assembly_name != "") %>%
  select(Strain, geneCount, Type, Strain_mixture)

diff_geneCount_ass_map <- geneCountMapping %>%
  group_by(Strain) %>%
  summarise(Difference_genes = abs(diff(geneCount))) %>%
  left_join(ancientGenomes_5X, by = c("Strain"="Genome_ancient")) %>%
  left_join(mutans_metadata)

diff_geneCount_ass_map %>%
  ggplot(aes(x=Mean_coverage, y=Difference_genes, colour = Proportion_Het_SNPs)) +
  geom_point(aes(shape=Strain_mixture)) +
  facet_wrap( ~ Strain_mixture)


diff_geneCount_ass_map %>%
  ggplot(aes(x=Proportion_Het_SNPs, y=Difference_genes, colour = Strain_mixture)) +
  geom_point(aes(shape=Strain_mixture))

  

geneCountMapping %>%
  select(Strain, geneCount, Type, Strain_mixture) %>%
  rbind(geneCountStrain) %>%
  ggplot(aes(x=Strain, y=geneCount, colour = Strain_mixture)) +
  geom_point(aes(shape=Type)) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

#Differing genes


differingGenes <- geneCountSpecies %>%
  group_by(Gene) %>%
  summarise(count=n()) %>%
  filter(count == 1)

differingCoreGenes <- geneCountSpecies %>%
  filter(GeneType == "Core genes") %>%
  group_by(Gene) %>%
  summarise(count=n()) %>%
  filter(count == 1)

differingGenes_90complete <- geneCountSpecies_90complete %>%
  group_by(Gene) %>%
  summarise(count=n()) %>%
  filter(count == 1)

differingCoreGenes_90complete <- geneCountSpecies_90complete %>%
  filter(GeneType == "Core genes") %>%
  group_by(Gene) %>%
  summarise(count=n()) %>%
  filter(count == 1)

CoreAncient <- geneCountSpecies_90complete %>%
  filter(Gene %in% differingCoreGenes_90complete$Gene) %>%
  filter(Age == "Ancient" & GeneType == "Core genes")

geneCountSpecies %>% filter(Gene %in% CoreAncient$Gene) %>% filter(Age == "Modern")

CoreModern <- geneCountSpecies_90complete %>%
  filter(Gene %in% differingCoreGenes_90complete$Gene) %>%
  filter(Age == "Modern" & GeneType == "Core genes") %>%
  left_join(info_depth_breath_cov)

#Figures ##Correlation between number of genes vs contamination vs coverage to ref.

DataGenesStats <- geneGenome %>%
  left_join(mutans_metadata, by = c("Genome" = "Assembly")) %>%
  filter(!is.na(Completeness)) %>%
  left_join(ancientGenomes_5X, by = c("Strain" = "Genome_ancient"))

genesvscompleteness <- DataGenesStats %>%
  ggplot(aes(x=Genes, y=Completeness, colour = Contamination)) +
  geom_point(aes(shape=Data)) +
  theme_light() #+
  #theme(legend.position = "none", plot.margin = margin(r=0))

genesvsmeancoverage <- DataGenesStats %>%
  ggplot(aes(x=Genes, y= Mean_coverage, colour = Contamination)) +
  geom_point(aes(shape=Data)) +
  ylab("Mean Coverage") +
  theme_light()


genesvscompletenessStrain <- DataGenesStats %>%
  ggplot(aes(x=Genes, y=Completeness, colour = Strain_mixture)) +
  geom_point(aes(shape=Data)) +
  labs(colour = "Strain mixture?") +
  theme_light() +
  #theme(legend.position = "none") +
  theme(legend.title = element_text(size = 10))#, #plot.margin = margin(r=0)) 

genesvsmeancoverageStrain <- DataGenesStats %>%
  ggplot(aes(x=Genes, y= Mean_coverage, colour = Strain_mixture)) +
  geom_point(aes(shape=Data)) +
  ylab("Mean Coverage") +
  labs(colour = "Strain mixture?") +
  theme_light() +
  theme(legend.title = element_text(size = 10))

genesvsdating_completeness <- DataGenesStats %>%
  ggplot(aes(x=Genes, y=Completeness, colour = Dating)) +
  geom_point(aes(shape=Data)) +
  scale_colour_viridis_c() +
  theme_light()
  
genesvsdating_meancov <- DataGenesStats %>%
  ggplot(aes(x=Genes, y=Mean_coverage, colour = Dating)) +
  geom_point(aes(shape=Data)) +
  scale_colour_viridis_c() +
  theme_light()


legend_1 <- get_legend(genesvscompleteness)

legend_2 <- get_legend(genesvscompletenessStrain)
 
legend_3 <- get_legend(genesvsdating_completeness)

legends <- ggarrange(legend_1, legend_2, legend_3, nrow = 3)


rm_legend <- function(p){p + theme(legend.position = "none")}
plots <- ggarrange(rm_legend(genesvscompleteness),
                   rm_legend(genesvsmeancoverage),
                   rm_legend(genesvscompletenessStrain),
                   rm_legend(genesvsmeancoverageStrain),
                   rm_legend(genesvsdating_completeness),
                   rm_legend(genesvsdating_meancov),
                    nrow = 3, ncol = 2, labels = c("A", "B","C","D", "E","F"), align = "hv")
ggarrange(plots, legends, widths = c(0.75,0.25))

ggarrange(plots, legends, widths = c(0.85,0.15))

ggsave("../Figures/Supplemetary_Figure_4_geneCounts_ancient.pdf",device = "pdf", units = "cm", height = 25, width = 23)

##Barplot core vs accessory genes

geneCountSpecies_90complete %>%
  mutate(GeneType = ifelse(GeneType == "Core genes", "Core", "Accessory")) %>%
  group_by(Age,GeneType) %>%
  summarise(GeneTotal = n()) %>%
ggplot(aes(x=Age, y=GeneTotal, fill = GeneType)) +
  geom_bar(position= "fill", stat = "identity") +
  scale_fill_manual(values = c("#b5e6e6ff","#8362b7ff")) +
  labs(fill = "Gene Type", x = "", y = "Proportion of pangenome") +
  theme_light() +
  theme(legend.position="right") +
  scale_x_discrete(labels= c("Ancient" = "Ancient\n(n=4,580)", "Modern" = "Modern\n(n=9,636)"))

ggsave("../Figures/PanelD_normalised_Figure4_CorevsAccessory_ancientVSmodern.pdf", device = "pdf", units = "cm", height = 17, width = 15)


geneCountSpecies_90complete %>%
  mutate(GeneType = ifelse(GeneType == "Core genes", "Core", "Accessory")) %>%
  group_by(Age,GeneType) %>%
  summarise(GeneTotal = n()) %>%
ggplot(aes(x=Age, y=GeneTotal, fill = GeneType)) +
  geom_bar(position= "stack", stat = "identity") +
  scale_fill_manual(values = c("#b5e6e6ff","#8362b7ff")) +
  labs(fill = "Gene Type", x = "", y = "Proportion of pangenome") +
  theme_light() +
  theme(legend.position="right") +
  scale_x_discrete(labels= c("Ancient" = "Ancient\n(n=31)", "Modern" = "Modern\n(n=456)"))

ggsave("../Figures/PanelD_raw_Figure4_CorevsAccessory_ancientVSmodern.pdf", device = "pdf", units = "cm", height = 17, width = 15)


geneCountSpecies_90complete %>%
  filter(Age == "Ancient" & GeneType == "Core genes") %>%
  filter(Gene %in% coreGenesAll$Gene) %>%
  nrow()
[1] 807
geneCountSpecies_90complete %>%
  filter(Gene %in% coreGenesAll$Gene) %>%
  filter(Age == "Ancient") %>%
  group_by(GeneType) %>%
  summarise(Total = n())

nonCoreAncient_coreAll <- geneCountSpecies_90complete %>%
  filter(Gene %in% coreGenesAll$Gene) %>%
  filter(Age == "Ancient" & GeneType != "Core genes") %>%
  mutate(Percentage = Total/31*100)

mean(nonCoreAncient_coreAll$Percentage)
[1] 78.98965
sd(nonCoreAncient_coreAll$Percentage)
[1] 11.11476
  

##Box plots number genes


modern_ancient90completenes <- mutans_metadata %>% 
  filter(Age == "Modern" | Completeness > 90)

#Boxplot without stats
geneGenome %>%
  mutate(Type = "Assembly") %>% 
  rbind(geneCountStrainAssembled %>% 
          select(Strain,geneCount, Type) %>% 
          rename(Genome = Strain, Genes = geneCount)) %>% 
  rbind(geneCountMappingAssembled %>% 
          filter(Type == "Mapping") %>% 
          select(Strain, geneCount, Type) %>% 
          rename(Genome = Strain, Genes = geneCount)) %>%
  left_join(mutans_metadata, by = c("Genome" = "Assembly")) %>%
  mutate(Age = ifelse(is.na(Age), "Ancient", Age)) %>%
  ggplot(aes(x=fct_infreq(Age), y=Genes, colour = Type)) +
  geom_boxplot(outlier.colour="red",
                outlier.size=1) +
  stat_compare_means(comparisons =)

  labs(color = "Age", x = "Age", y = "Total gene count/genome") +
  theme_light() +
  theme(axis.text.x = element_text(angle=45,hjust=1), 
        legend.position="right")
NULL
  #Complex boxplot with stats
  geneGenome %>%
  mutate(Type = "") %>% 
  rbind(geneCountStrainAssembled %>% 
          select(Strain,geneCount, Type) %>% 
          rename(Genome = Strain, Genes = geneCount)) %>% 
  rbind(geneCountMappingAssembled %>% 
          filter(Type == "Ancient Mapping") %>% 
          select(Strain, geneCount, Type) %>% 
          rename(Genome = Strain, Genes = geneCount)) %>%
  left_join(mutans_metadata, by = c("Genome" = "Assembly")) %>%
    mutate(Type = case_when(
      Age == "Modern" ~ "Assembly modern",
      Age == "Ancient" & Type == "" ~ "Assembly ancient",
      .default = Type
    )) %>%
  ggstatsplot::ggbetweenstats(x = Type, y = Genes, type = "r")

 
  #Box plot with stats, with ancient >90% complete 
  geneGenome %>%
    mutate(Type = "") %>% 
    rbind(geneCountStrainAssembled %>% 
              select(Strain,geneCount, Type) %>% 
              rename(Genome = Strain, Genes = geneCount)) %>% 
    rbind(geneCountMappingAssembled %>% 
              filter(Type == "Ancient Mapping") %>% 
              select(Strain, geneCount, Type) %>% 
              rename(Genome = Strain, Genes = geneCount)) %>%
    left_join(mutans_metadata, by = c("Genome" = "Assembly")) %>%
    mutate(Type = case_when(
        Age == "Modern" ~ "Assembly modern",
        Age == "Ancient" & Type == "" ~ "Assembly ancient",
        .default = Type
    )) %>% 
    filter(Genome %in% modern_ancient90completenes$Assembly | Genome %in% modern_ancient90completenes$Strain | grepl("PAN0",Genome)) %>%
    ggstatsplot::ggbetweenstats(x = Type, y = Genes, type = "r")

  ggsave("../Figures/Supplementary_figure_3_genomesize_comparison.pdf", device = "pdf", units = "cm", height = 15, width = 23)

##Genes differing between assembly and mapping

diff_genes_assembly_mapping <- PA_matrix_only_ancient %>%
  filter(Assembly_name != "") %>%
  group_by(Gene,Assembly_name) %>%
  summarise(total = sum(Condition)) %>%
  group_by(Gene, total) %>%
  summarise(concordance = n()) %>%
  spread(total, concordance) %>%
  filter(!is.na(`1`)) %>%
  mutate(Proportion_concordance = `2`/(`1`+`2`)) %>%
  left_join(geneCount %>% select(Gene, GeneType))

geneFound1methodGenome <- diff_genes_assembly_mapping %>% 
  filter(is.na(Proportion_concordance)) %>% 
  left_join(PA_matrix_only_ancient) %>% 
  filter(Assembly_name != "") %>% 
  group_by(Gene,Type) %>% 
  summarise(Total = n()) %>% 
  left_join(geneCount %>% 
              select(Gene, GeneType))

genesFoundOnly1method <- geneFound1methodGenome %>% 
  group_by(Gene) %>% 
  summarise(total = n()) %>% 
  filter(total == 1) %>% 
  select(Gene)

#geneFound1methodGenome %>% 
#  filter(Gene %in% genesFoundOnly1method$Gene) %>% 
#  group_by(Type, GeneType) %>%
#  summarise(geneCount = n()) +
#  ggplot(aes(x=GeneType, y=GeneTotal, fill = Age)) +
#  geom_bar(position= "dodge", stat="identity") +
#  labs(color = "Age", x = "Age", y = "Total gene count/genome") +
#  theme_bw() +
#  theme(axis.text.x = element_text(angle=45,hjust=1), 
#        legend.position="right")

ancient_breadth_depth_cov %>% filter(Gene %in% genesFoundOnly1method$Gene) %>% 
  left_join(geneCount %>% 
              select(Gene, GeneType)) %>%
  filter(GeneType == "Core genes")
LS0tCnRpdGxlOiAiUGFuZ2Vub21lIG11dGFucyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQojUmVxdWlyZWQgbGlicmFyaWVzCmBgYHtyfQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdncHVicikKYGBgCgojUmVhZGluZyBtZXRhZGF0YSBhbmQgcHJlc2VuY2UvYWJzZW5jZSBtYXRyaXgKYGBge3J9Cm11dGFuc19tZXRhZGF0YSA8LSByZWFkLmNzdihmaWxlID0gIi4uL0RhdGEvTWV0YWRhdGFfcGFuZ2Vub21lX2FuYWx5c2lzLmNzdiIpCgpQQV9tYXRyaXhfdHJ1ZSA8LSByZWFkLmRlbGltKGZpbGUgPSAiLi4vRGF0YS9yb2FyeV85NV9hbmNpZW50QXNzZW1ibGllc19nZW5lX3ByZXNlbmNlX2Fic2VuY2UuUnRhYiIpCgpQQV9tYXRyaXhfdHJ1ZV90IDwtIFBBX21hdHJpeF90cnVlWywtMV0Kcm93bmFtZXMoUEFfbWF0cml4X3RydWVfdCkgPC0gUEFfbWF0cml4X3RydWVbLDFdClBBX21hdHJpeF90cnVlX3QgPC0gdChQQV9tYXRyaXhfdHJ1ZV90KQoKUEFfbWF0cml4IDwtIHJlYWQuZGVsaW0oZmlsZSA9ICIuLi9EYXRhL3JvYXJ5Xzk1X2FuY2llbnRBc3NlbWJsaWVzX2dlbmVfcHJlc2VuY2VfYWJzZW5jZS5SdGFiIikgJT4lCiAgZ2F0aGVyKEdlbm9tZSwgQ29uZGl0aW9uLCAyOm5jb2woUEFfbWF0cml4X3RydWUpKSAlPiUKICBmaWx0ZXIoQ29uZGl0aW9uICE9ICIwIikKCmBgYAojQmFzaWMgc3RhdGlzdGljcwpgYGB7cn0KZ2VuZUdlbm9tZSA8LSBQQV9tYXRyaXggJT4lCiAgZ3JvdXBfYnkoR2Vub21lKSAlPiUKICBzdW1tYXJpc2UoR2VuZXM9bigpKQoKZ2VuZUNvdW50IDwtIFBBX21hdHJpeCAlPiUKICBsZWZ0X2pvaW4obXV0YW5zX21ldGFkYXRhLCBieSA9IGMoIkdlbm9tZSIgPSAiQXNzZW1ibHkiKSkgJT4lCiAgZ3JvdXBfYnkoR2VuZSkgJT4lCiAgc3VtbWFyaXNlKFRvdGFsID0gc3VtKENvbmRpdGlvbikpICU+JQogIG11dGF0ZShHZW5lVHlwZSA9CiAgICAgICAgICAgY2FzZV93aGVuKAogICAgICAgICAgICAgVG90YWwgPiAoNDkyKjAuOTUpIH4gIkNvcmUgZ2VuZXMiLAogICAgICAgICAgICAgVG90YWwgPCAoNDkyKjAuMTUpIH4gIkNsb3VkIGdlbmVzIiwKICAgICAgICAgICAgIC5kZWZhdWx0ID0gIlNoZWxsIGdlbmVzIgogICAgICAgICAgICkKICAgICAgICAgKQoKZ2VuZUNvdW50U3BlY2llcyA8LSBQQV9tYXRyaXggJT4lCiAgbGVmdF9qb2luKG11dGFuc19tZXRhZGF0YSwgYnkgPSBjKCJHZW5vbWUiID0gIkFzc2VtYmx5IikpICU+JQogIGdyb3VwX2J5KEdlbmUsQWdlKSAlPiUKICBzdW1tYXJpc2UoVG90YWwgPSBzdW0oQ29uZGl0aW9uKSkgJT4lCiAgbXV0YXRlKEdlbmVUeXBlID0KICAgICAgICAgICBjYXNlX3doZW4oCiAgICAgICAgICAgICBUb3RhbCA+PSAzMyAmIEFnZSA9PSAiQW5jaWVudCIgfiAiQ29yZSBnZW5lcyIsCiAgICAgICAgICAgICBUb3RhbCA+ICg0NTYqMC45NSkgJiBBZ2UgPT0gIk1vZGVybiIgfiAiQ29yZSBnZW5lcyIsIAogICAgICAgICAgICAgVG90YWwgPCAoMzUqMC4xNSkgJiBBZ2UgPT0gIkFuY2llbnQiIH4gIkNsb3VkIGdlbmVzIiwKICAgICAgICAgICAgIFRvdGFsIDwgKDQ1NiowLjE1KSAmIEFnZSA9PSAiTW9kZXJuIiB+ICJDbG91ZCBnZW5lcyIsCiAgICAgICAgICAgICAuZGVmYXVsdCA9ICJTaGVsbCBnZW5lcyIKICAgICAgICAgICApCiAgICAgICAgICkKCmdlbmVDb3VudFNwZWNpZXNfOTBjb21wbGV0ZSA8LSBQQV9tYXRyaXggJT4lCiAgbGVmdF9qb2luKG11dGFuc19tZXRhZGF0YSwgYnkgPSBjKCJHZW5vbWUiID0gIkFzc2VtYmx5IikpICU+JQogIGZpbHRlcihDb21wbGV0ZW5lc3MgPj05MCB8IGlzLm5hKENvbXBsZXRlbmVzcykpICU+JQogIGdyb3VwX2J5KEdlbmUsQWdlKSAlPiUKICBzdW1tYXJpc2UoVG90YWwgPSBzdW0oQ29uZGl0aW9uKSkgJT4lCiAgbXV0YXRlKEdlbmVUeXBlID0KICAgICAgICAgICBjYXNlX3doZW4oCiAgICAgICAgICAgICBUb3RhbCA+PSAyOSAmIEFnZSA9PSAiQW5jaWVudCIgfiAiQ29yZSBnZW5lcyIsCiAgICAgICAgICAgICBUb3RhbCA+ICg0NTYqMC45NSkgJiBBZ2UgPT0gIk1vZGVybiIgfiAiQ29yZSBnZW5lcyIsIAogICAgICAgICAgICAgVG90YWwgPCAoMzEqMC4xNSkgJiBBZ2UgPT0gIkFuY2llbnQiIH4gIkNsb3VkIGdlbmVzIiwKICAgICAgICAgICAgIFRvdGFsIDwgKDQ1NiowLjE1KSAmIEFnZSA9PSAiTW9kZXJuIiB+ICJDbG91ZCBnZW5lcyIsCiAgICAgICAgICAgICAuZGVmYXVsdCA9ICJTaGVsbCBnZW5lcyIKICAgICAgICAgICApCiAgICAgICAgICkKCmdlbmVQcmVzZW50NVBlcmNlbnQgPC0gUEFfbWF0cml4ICU+JQogIGdyb3VwX2J5KEdlbmUpICU+JQogIHN1bW1hcmlzZShUb3RhbCA9IHN1bShDb25kaXRpb24pKSAgJT4lCiAgbXV0YXRlKFBlcmNlbnRhZ2UgPSBUb3RhbC80OTEqMTAwKSAlPiUKICBmaWx0ZXIoUGVyY2VudGFnZSA+PSAxNSkKICAKZ2VuZUNvdW50U3BlY2llcyAlPiUKICBncm91cF9ieShBZ2UsR2VuZVR5cGUpICU+JQogIHN1bW1hcmlzZShHZW5lVG90YWwgPSBuKCkpICU+JQpnZ3Bsb3QoYWVzKHg9R2VuZVR5cGUsIHk9R2VuZVRvdGFsLCBmaWxsID0gQWdlKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uPSAiZG9kZ2UiLCBzdGF0PSJpZGVudGl0eSIpICsKICBsYWJzKGNvbG9yID0gIkFnZSIsIHggPSAiQWdlIiwgeSA9ICJUb3RhbCBnZW5lIGNvdW50L2dlbm9tZSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSxoanVzdD0xKSwgCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJyaWdodCIpCgpnZW5lQ291bnRTcGVjaWVzXzkwY29tcGxldGUgJT4lCiAgZ3JvdXBfYnkoQWdlLEdlbmVUeXBlKSAlPiUKICBzdW1tYXJpc2UoR2VuZVRvdGFsID0gbigpKSAlPiUKZ2dwbG90KGFlcyh4PUdlbmVUeXBlLCB5PUdlbmVUb3RhbCwgZmlsbCA9IEFnZSkpICsKICBnZW9tX2Jhcihwb3NpdGlvbj0gImRvZGdlIiwgc3RhdD0iaWRlbnRpdHkiKSArCiAgbGFicyhjb2xvciA9ICJBZ2UiLCB4ID0gIkFnZSIsIHkgPSAiVG90YWwgZ2VuZSBjb3VudC9nZW5vbWUiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsaGp1c3Q9MSksIAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0icmlnaHQiKQoKY29yZUdlbmVzQWxsIDwtIGdlbmVDb3VudCAlPiUgZmlsdGVyKEdlbmVUeXBlID09ICJDb3JlIGdlbmVzIikKY29yZUdlbmVzU2hhcmVkIDwtIGdlbmVDb3VudFNwZWNpZXMgJT4lIGZpbHRlcihHZW5lVHlwZSA9PSAiQ29yZSBnZW5lcyIpICU+JSBncm91cF9ieShHZW5lKSAlPiUgc3VtbWFyaXNlKHRvdGFsID0gbigpKSAlPiUgZmlsdGVyKHRvdGFsID09IDIpICU+JSBmaWx0ZXIoR2VuZSAlaW4lIGNvcmVHZW5lc0FsbCRHZW5lKQpub25Db3JlQW5jaWVudCA8LSBnZW5lQ291bnRTcGVjaWVzXzkwY29tcGxldGUgJT4lIGZpbHRlcihBZ2UgPT0gIkFuY2llbnQiKSAlPiUgZmlsdGVyKEdlbmUgJWluJSBjb3JlR2VuZXNBbGwkR2VuZSkgJT4lIGZpbHRlcighR2VuZSAlaW4lIGNvcmVHZW5lc1NoYXJlZCRHZW5lKQpgYGAKCiMgUHJvYmVzX2NvdmVyYWdlCmBgYHtyfQppbmZvX2JyZWF0aF9jb3ZlcmFnZSA8LSByZWFkLmRlbGltKCIuLi9EYXRhL3Byb2Jlc19jaGlwQV9jaGlwQl9jb21iaW5lZF9ybWR1cC5icmVhZHRoIiwgaGVhZGVyID0gRkFMU0UsIGNvbC5uYW1lcyA9IGMoIkdlbmVfcm9hcnkiLCAiU3RhcnQiLCAiRW5kIiwgIk5yX2ZlYXR1cmVzIiwgIkJhc2VzX2NvdiIsIkxlbmd0aCIsICJQZXJjZW50X2NvdmVyYWdlIiApKSAlPiUgc2VsZWN0KEdlbmVfcm9hcnksIExlbmd0aCwgUGVyY2VudF9jb3ZlcmFnZSkKCmluZm9fZGVwdGhfY292ZXJhZ2UgPC0gcmVhZC5kZWxpbSgiLi4vRGF0YS9wcm9iZXNfY2hpcEFfY2hpcEJfY29tYmluZWRfcm1kdXAuZGVwdGgiLGhlYWRlciA9IEZBTFNFLCBjb2wubmFtZXMgPSBjKCJHZW5lX3JvYXJ5IiwiU3RhcnQiLCAiRW5kIiwgIkRlcHRoX2NvdmVyYWdlIikpICU+JSBzZWxlY3QoR2VuZV9yb2FyeSwgRGVwdGhfY292ZXJhZ2UpCgpnZW5lX3ByZXNlbmNlX2Fic2VuY2VfY3N2IDwtIHJlYWQuY3N2KGZpbGUgPSAiLi4vRGF0YS9nZW5lX3ByZXNlbmNlX2Fic2VuY2UuY3N2IikgJT4lCiAgZ2F0aGVyKEdlbm9tZSwgR2VuZV9yb2FyeSwgMTU6NTA1KSAlPiUKICBzZXBhcmF0ZShHZW5lX3JvYXJ5LCBzZXAgPSAiXHQiLCBjKCJHZW5lX3JvYXJ5IiwiR2VuZV9yb2FyeV9kdXBsaWNhdGUiLCAiR2VuZV9yb2FyeV9kdXBsaWNhdGVfMiIsICJHZW5lX3JvYXJ5X2R1cGxpY2F0ZV8zIiwgIkdlbmVfcm9hcnlfZHVwbGljYXRlXzQiLCAiR2VuZV9yb2FyeV9kdXBsaWNhdGVfNSIsICJHZW5lX3JvYXJ5X2R1cGxpY2F0ZV82IiwgIkdlbmVfcm9hcnlfZHVwbGljYXRlXzciLCAiR2VuZV9yb2FyeV9kdXBsaWNhdGVfOCIpKSAlPiUKICBmaWx0ZXIoR2VuZV9yb2FyeSAhPSIiKQoKaW5mb19kZXB0aF9icmVhdGhfY292IDwtIGluZm9fZGVwdGhfY292ZXJhZ2UgJT4lIGZ1bGxfam9pbihpbmZvX2JyZWF0aF9jb3ZlcmFnZSkgJT4lCiAgbGVmdF9qb2luKGdlbmVfcHJlc2VuY2VfYWJzZW5jZV9jc3YpCiAgCm5vY292ZXJhZ2VfcHJvYmVzIDwtIGluZm9fZGVwdGhfYnJlYXRoX2NvdiAlPiUgCiAgZmlsdGVyKFBlcmNlbnRfY292ZXJhZ2UgPCAwLjkpICU+JSAKICBsZWZ0X2pvaW4oZ2VuZUNvdW50U3BlY2llcykKCm9ubHlwcmVzZW50b25jZSA8LSBub2NvdmVyYWdlX3Byb2JlcyAlPiUgCiAgZ3JvdXBfYnkoR2VuZV9yb2FyeSkgJT4lIAogIHN1bW1hcmlzZShUb3RhbD0gbigpKSAlPiUgCiAgZmlsdGVyKFRvdGFsID09IDEpCgpub2NvdmVyYWdlX3Byb2Jlc19ub3RpbmFuY2llbnRhc3NlbWJsaWVzIDwtIG5vY292ZXJhZ2VfcHJvYmVzICU+JQogIGZpbHRlcihHZW5lX3JvYXJ5ICVpbiUgb25seXByZXNlbnRvbmNlJEdlbmVfcm9hcnkpICU+JQogIGZpbHRlcihBZ2UgPT0gIk1vZGVybiIpCgpub2NvdmVyYWdlX3Byb2JlcyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBQZXJjZW50X2NvdmVyYWdlLCBncm91cCA9IEdlbmVUeXBlKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxMDApICsKICBmYWNldF93cmFwKCB+IEdlbmVUeXBlKQoKbm9jb3ZlcmFnZV9wcm9iZXMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gTm8uLmlzb2xhdGVzKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxMDApCmBgYAoKI1JlYWRpbmcgbWFwcGluZyBjb3ZlcmFnZSAoYnJlYWR0aCBhbmQgZGVwdGgpIGFuY2llbnQgZ2Vub21lcwpgYGB7cn0KYW5jaWVudF9nZW5vbWVzX2Fzc2VtYmx5IDwtIG11dGFuc19tZXRhZGF0YSAlPiUgCiAgZmlsdGVyKEFnZSA9PSAiQW5jaWVudCIpCmFuY2llbnRHZW5vbWVzXzVYIDwtIHJlYWQuZGVsaW0oIi4uL0RhdGEvbWV0YWRhdGFfYW5jaWVudF9nZW5vbWVzX2NvdmVyYWdlLmNzdiIsIHNlcCA9ICIsIikKZGVwdGhfY292ZXJhZ2VfYW5jaWVudCA8LSByZWFkX2RlbGltKGZpbGUgPSAiLi4vRGF0YS9wYW5nZW5vbWVfbXV0YW5zLmRlcHRoLmJlZCIsIGNvbF9uYW1lcyA9IGMoIkdlbm9tZV9hbmNpZW50IiwiR2VuZV9yb2FyeSIsInN0YXJ0IiwiZW5kIiwiZGVwdGgiKSkKCmJyZWFkdGhfY292ZXJhZ2VfYW5jaWVudCA8LSByZWFkX2RlbGltKGZpbGUgPSAiLi4vRGF0YS9wYW5nZW5vbWVfbXV0YW5zLmJyZWFkdGguYmVkIiwgY29sX25hbWVzID0gYygiR2Vub21lX2FuY2llbnQiLCJHZW5lX3JvYXJ5IiwiYnJlYWR0aCIpKQoKZGVwdGhfYnJlYWR0aF9jb3ZlcmFnZV9hbmNpZW50IDwtIGRlcHRoX2NvdmVyYWdlX2FuY2llbnQgJT4lIGxlZnRfam9pbihicmVhZHRoX2NvdmVyYWdlX2FuY2llbnQpICU+JQogIGxlZnRfam9pbihnZW5lX3ByZXNlbmNlX2Fic2VuY2VfY3N2KQoKYW5jaWVudF9icmVhZHRoX2RlcHRoX2NvdiA8LSBkZXB0aF9icmVhZHRoX2NvdmVyYWdlX2FuY2llbnQgJT4lCiAgZmlsdGVyKEdlbm9tZV9hbmNpZW50ICVpbiUgYW5jaWVudEdlbm9tZXNfNVgkR2Vub21lKSAlPiUKICBsZWZ0X2pvaW4oYW5jaWVudEdlbm9tZXNfNVgpICU+JQogIG11dGF0ZShkZXB0aF9jb3JyZWN0ZWQgPSBkZXB0aC9NZWFuX2NvdmVyYWdlLAogICAgICAgICBFeHBlY3RlZF9jb3ZlcmFnZSA9ICgxLWV4cCgtMC44ODMqTWVhbl9jb3ZlcmFnZSkpKQoKYW5jaWVudF9icmVhZHRoX2RlcHRoX2Nvdl9maWx0ZXJlZCA8LSBhbmNpZW50X2JyZWFkdGhfZGVwdGhfY292ICU+JSAKICBtdXRhdGUoQ29uZGl0aW9uID0gY2FzZV93aGVuKGJyZWFkdGggPj0gRGVwdGhfY292XzFYLzEwMCAmIGRlcHRoX2NvcnJlY3RlZCA+PSAwLjUgJiBkZXB0aF9jb3JyZWN0ZWQgPCAxLjI1IH4gMSwgLmRlZmF1bHQgPSAwKSMsCiAgICAgICAgICNDb25kaXRpb24yID0gY2FzZV93aGVuKGJyZWFkdGggPj0gRXhwZWN0ZWRfY292ZXJhZ2UgJiBkZXB0aF9jb3JyZWN0ZWQgPj0gMC41ICYgZGVwdGhfY29ycmVjdGVkIDwgMS4yNSB+IDEsIC5kZWZhdWx0ID0gMCkKICAgICAgICAgKQoKUEFfbWF0cml4X2FuY19tYXBwZWQgPC0gYW5jaWVudF9icmVhZHRoX2RlcHRoX2Nvdl9maWx0ZXJlZCAlPiUgCiAgZmlsdGVyKENvbmRpdGlvbiAhPSAwKSAlPiUKICBzZWxlY3QoR2VuZSwgR2Vub21lX2FuY2llbnQsIENvbmRpdGlvbikgJT4lCiAgcmVuYW1lKEdlbm9tZSA9IEdlbm9tZV9hbmNpZW50LCAKICAgICAgICAgI0NvbmRpdGlvbiA9IENvbmRpdGlvbjIKICAgICAgICAgKSAlPiUKICByYmluZChQQV9tYXRyaXgpCgptYXBfYXNzZW1fY29kZSA8LSByZWFkLmRlbGltKCIuLi9EYXRhL3N0cmFpbl9hc3NlbWJseS5jc3YiLCBzZXAgPSAiLCIpCgpQQV9tYXRyaXhfb25seV9hbmNpZW50IDwtIFBBX21hdHJpeF9hbmNfbWFwcGVkICU+JSAKICBmaWx0ZXIoZ3JlcGwoIlNNMXxNRUdBSElUfEtHSDJ8UEFOMCIsR2Vub21lKSkgJT4lCiAgbGVmdF9qb2luKG1hcF9hc3NlbV9jb2RlKSAlPiUKICBsZWZ0X2pvaW4oYW5jaWVudEdlbm9tZXNfNVgsIGJ5ID0gYygiU3RyYWluIj0iR2Vub21lX2FuY2llbnQiKSkKCmdlbmVDb3VudE1hcHBpbmcgPC0gUEFfbWF0cml4X29ubHlfYW5jaWVudCAlPiUKICBmaWx0ZXIoIWlzLm5hKEFzc2VtYmx5X25hbWUpKSAlPiUKICBncm91cF9ieShHZW5vbWUpICU+JQogIHN1bW1hcmlzZShnZW5lQ291bnQgPSBzdW0oQ29uZGl0aW9uKSkgJT4lCiAgbGVmdF9qb2luKG1hcF9hc3NlbV9jb2RlKSAlPiUKIyAgbGVmdF9qb2luKGdlbmVHZW5vbWUpICU+JQogIGxlZnRfam9pbihhbmNpZW50R2Vub21lc181WCwgYnkgPSBjKCJTdHJhaW4iPSJHZW5vbWVfYW5jaWVudCIpKQoKZ2VuZUNvdW50TWFwcGluZ0Fzc2VtYmxlZCA8LVBBX21hdHJpeF9vbmx5X2FuY2llbnQgJT4lCiAgZmlsdGVyKCFpcy5uYShBc3NlbWJseV9uYW1lKSkgJT4lCiAgZ3JvdXBfYnkoR2Vub21lKSAlPiUKICBzdW1tYXJpc2UoZ2VuZUNvdW50ID0gc3VtKENvbmRpdGlvbikpICU+JQogIGxlZnRfam9pbihtYXBfYXNzZW1fY29kZSkgJT4lCiAgbGVmdF9qb2luKGFuY2llbnRHZW5vbWVzXzVYLCBieSA9IGMoIlN0cmFpbiI9Ikdlbm9tZV9hbmNpZW50IikpICU+JQogIGZpbHRlcihBc3NlbWJseV9uYW1lICE9ICIiKQoKZ2VuZUNvdW50U3RyYWluIDwtIFBBX21hdHJpeF9vbmx5X2FuY2llbnQgJT4lCiAgZmlsdGVyKCFpcy5uYShBc3NlbWJseV9uYW1lKSkgJT4lCiAgZ3JvdXBfYnkoU3RyYWluLCBHZW5lKSAlPiUKICBzdW1tYXJpc2UoZ2VuZUNvdW50VG90YWwgPSBzdW0oQ29uZGl0aW9uKSkgJT4lCiAgbXV0YXRlKGdlbmVDb3VudENvcnJlY3RlZCA9IDEpICU+JQogIGdyb3VwX2J5KFN0cmFpbikgJT4lCiAgc3VtbWFyaXNlKGdlbmVDb3VudCA9IHN1bShnZW5lQ291bnRDb3JyZWN0ZWQpKSAlPiUKICBtdXRhdGUoVHlwZSA9ICJNZXJnZWQiKSAlPiUKICBsZWZ0X2pvaW4oYW5jaWVudEdlbm9tZXNfNVgsIGJ5ID0gYygiU3RyYWluIj0iR2Vub21lX2FuY2llbnQiKSkgJT4lCiAgc2VsZWN0KFN0cmFpbiwgZ2VuZUNvdW50LCBUeXBlLCBTdHJhaW5fbWl4dHVyZSkKCmdlbmVDb3VudFN0cmFpbkFzc2VtYmxlZCA8LSBQQV9tYXRyaXhfb25seV9hbmNpZW50ICU+JQogIGZpbHRlcighaXMubmEoQXNzZW1ibHlfbmFtZSkpICU+JQogIGdyb3VwX2J5KFN0cmFpbiwgR2VuZSkgJT4lCiAgc3VtbWFyaXNlKGdlbmVDb3VudFRvdGFsID0gc3VtKENvbmRpdGlvbikpICU+JQogIG11dGF0ZShnZW5lQ291bnRDb3JyZWN0ZWQgPSAxKSAlPiUKICBncm91cF9ieShTdHJhaW4pICU+JQogIHN1bW1hcmlzZShnZW5lQ291bnQgPSBzdW0oZ2VuZUNvdW50Q29ycmVjdGVkKSkgJT4lCiAgbXV0YXRlKFR5cGUgPSAiQW5jaWVudCBNZXJnZWQiKSAlPiUKICBsZWZ0X2pvaW4oYW5jaWVudEdlbm9tZXNfNVgsIGJ5ID0gYygiU3RyYWluIj0iR2Vub21lX2FuY2llbnQiKSkgJT4lCiAgZmlsdGVyKEFzc2VtYmx5X25hbWUgIT0gIiIpICU+JQogIHNlbGVjdChTdHJhaW4sIGdlbmVDb3VudCwgVHlwZSwgU3RyYWluX21peHR1cmUpCgpkaWZmX2dlbmVDb3VudF9hc3NfbWFwIDwtIGdlbmVDb3VudE1hcHBpbmcgJT4lCiAgZ3JvdXBfYnkoU3RyYWluKSAlPiUKICBzdW1tYXJpc2UoRGlmZmVyZW5jZV9nZW5lcyA9IGFicyhkaWZmKGdlbmVDb3VudCkpKSAlPiUKICBsZWZ0X2pvaW4oYW5jaWVudEdlbm9tZXNfNVgsIGJ5ID0gYygiU3RyYWluIj0iR2Vub21lX2FuY2llbnQiKSkgJT4lCiAgbGVmdF9qb2luKG11dGFuc19tZXRhZGF0YSkKCmRpZmZfZ2VuZUNvdW50X2Fzc19tYXAgJT4lCiAgZ2dwbG90KGFlcyh4PU1lYW5fY292ZXJhZ2UsIHk9RGlmZmVyZW5jZV9nZW5lcywgY29sb3VyID0gUHJvcG9ydGlvbl9IZXRfU05QcykpICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZT1TdHJhaW5fbWl4dHVyZSkpICsKICBmYWNldF93cmFwKCB+IFN0cmFpbl9taXh0dXJlKQoKZGlmZl9nZW5lQ291bnRfYXNzX21hcCAlPiUKICBnZ3Bsb3QoYWVzKHg9UHJvcG9ydGlvbl9IZXRfU05QcywgeT1EaWZmZXJlbmNlX2dlbmVzLCBjb2xvdXIgPSBTdHJhaW5fbWl4dHVyZSkpICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZT1TdHJhaW5fbWl4dHVyZSkpCiAgCgpnZW5lQ291bnRNYXBwaW5nICU+JQogIHNlbGVjdChTdHJhaW4sIGdlbmVDb3VudCwgVHlwZSwgU3RyYWluX21peHR1cmUpICU+JQogIHJiaW5kKGdlbmVDb3VudFN0cmFpbikgJT4lCiAgZ2dwbG90KGFlcyh4PVN0cmFpbiwgeT1nZW5lQ291bnQsIGNvbG91ciA9IFN0cmFpbl9taXh0dXJlKSkgKwogIGdlb21fcG9pbnQoYWVzKHNoYXBlPVR5cGUpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKQoKYGBgCgojRGlmZmVyaW5nIGdlbmVzCmBgYHtyfQoKZGlmZmVyaW5nR2VuZXMgPC0gZ2VuZUNvdW50U3BlY2llcyAlPiUKICBncm91cF9ieShHZW5lKSAlPiUKICBzdW1tYXJpc2UoY291bnQ9bigpKSAlPiUKICBmaWx0ZXIoY291bnQgPT0gMSkKCmRpZmZlcmluZ0NvcmVHZW5lcyA8LSBnZW5lQ291bnRTcGVjaWVzICU+JQogIGZpbHRlcihHZW5lVHlwZSA9PSAiQ29yZSBnZW5lcyIpICU+JQogIGdyb3VwX2J5KEdlbmUpICU+JQogIHN1bW1hcmlzZShjb3VudD1uKCkpICU+JQogIGZpbHRlcihjb3VudCA9PSAxKQoKZGlmZmVyaW5nR2VuZXNfOTBjb21wbGV0ZSA8LSBnZW5lQ291bnRTcGVjaWVzXzkwY29tcGxldGUgJT4lCiAgZ3JvdXBfYnkoR2VuZSkgJT4lCiAgc3VtbWFyaXNlKGNvdW50PW4oKSkgJT4lCiAgZmlsdGVyKGNvdW50ID09IDEpCgpkaWZmZXJpbmdDb3JlR2VuZXNfOTBjb21wbGV0ZSA8LSBnZW5lQ291bnRTcGVjaWVzXzkwY29tcGxldGUgJT4lCiAgZmlsdGVyKEdlbmVUeXBlID09ICJDb3JlIGdlbmVzIikgJT4lCiAgZ3JvdXBfYnkoR2VuZSkgJT4lCiAgc3VtbWFyaXNlKGNvdW50PW4oKSkgJT4lCiAgZmlsdGVyKGNvdW50ID09IDEpCgpDb3JlQW5jaWVudCA8LSBnZW5lQ291bnRTcGVjaWVzXzkwY29tcGxldGUgJT4lCiAgZmlsdGVyKEdlbmUgJWluJSBkaWZmZXJpbmdDb3JlR2VuZXNfOTBjb21wbGV0ZSRHZW5lKSAlPiUKICBmaWx0ZXIoQWdlID09ICJBbmNpZW50IiAmIEdlbmVUeXBlID09ICJDb3JlIGdlbmVzIikKCm5vbkNvcmVNb2Rlcm5fQ29yZUFuY2llbnQgPC0gZ2VuZUNvdW50U3BlY2llcyAlPiUgCiAgZmlsdGVyKEdlbmUgJWluJSBDb3JlQW5jaWVudCRHZW5lKSAlPiUgCiAgZmlsdGVyKEFnZSA9PSAiTW9kZXJuIikKCm5vbkNvcmVNb2Rlcm5fQ29yZUFuY2llbnQgJT4lIGxlZnRfam9pbihnZW5lX3ByZXNlbmNlX2Fic2VuY2VfY3N2KSAlPiUgc2VsZWN0KEdlbmUsQXZnLnNlcXVlbmNlcy5wZXIuaXNvbGF0ZSxBbm5vdGF0aW9uLFRvdGFsLEdlbmVUeXBlKSAlPiUgZGlzdGluY3QoKSAlPiUgd3JpdGVfZGVsaW0oZmlsZSA9ICIuLi9EYXRhL25vbkNvcmVNb2Rlcm5fQ29yZUFuY2llbnQudHN2IiwgZGVsaW0gPSAiXHQiKQogIApDb3JlTW9kZXJuIDwtIGdlbmVDb3VudFNwZWNpZXNfOTBjb21wbGV0ZSAlPiUKICBmaWx0ZXIoR2VuZSAlaW4lIGRpZmZlcmluZ0NvcmVHZW5lc185MGNvbXBsZXRlJEdlbmUpICU+JQogIGZpbHRlcihBZ2UgPT0gIk1vZGVybiIgJiBHZW5lVHlwZSA9PSAiQ29yZSBnZW5lcyIpICU+JQogIGxlZnRfam9pbihpbmZvX2RlcHRoX2JyZWF0aF9jb3YpCmBgYAoKI0ZpZ3VyZXMKIyNDb3JyZWxhdGlvbiBiZXR3ZWVuIG51bWJlciBvZiBnZW5lcyB2cyBjb250YW1pbmF0aW9uIHZzIGNvdmVyYWdlIHRvIHJlZi4KYGBge3J9CkRhdGFHZW5lc1N0YXRzIDwtIGdlbmVHZW5vbWUgJT4lCiAgbGVmdF9qb2luKG11dGFuc19tZXRhZGF0YSwgYnkgPSBjKCJHZW5vbWUiID0gIkFzc2VtYmx5IikpICU+JQogIGZpbHRlcighaXMubmEoQ29tcGxldGVuZXNzKSkgJT4lCiAgbGVmdF9qb2luKGFuY2llbnRHZW5vbWVzXzVYLCBieSA9IGMoIlN0cmFpbiIgPSAiR2Vub21lX2FuY2llbnQiKSkKCmdlbmVzdnNjb21wbGV0ZW5lc3MgPC0gRGF0YUdlbmVzU3RhdHMgJT4lCiAgZ2dwbG90KGFlcyh4PUdlbmVzLCB5PUNvbXBsZXRlbmVzcywgY29sb3VyID0gQ29udGFtaW5hdGlvbikpICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZT1EYXRhKSkgKwogIHRoZW1lX2xpZ2h0KCkgIysKICAjdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwbG90Lm1hcmdpbiA9IG1hcmdpbihyPTApKQoKZ2VuZXN2c21lYW5jb3ZlcmFnZSA8LSBEYXRhR2VuZXNTdGF0cyAlPiUKICBnZ3Bsb3QoYWVzKHg9R2VuZXMsIHk9IE1lYW5fY292ZXJhZ2UsIGNvbG91ciA9IENvbnRhbWluYXRpb24pKSArCiAgZ2VvbV9wb2ludChhZXMoc2hhcGU9RGF0YSkpICsKICB5bGFiKCJNZWFuIENvdmVyYWdlIikgKwogIHRoZW1lX2xpZ2h0KCkKCgpnZW5lc3ZzY29tcGxldGVuZXNzU3RyYWluIDwtIERhdGFHZW5lc1N0YXRzICU+JQogIGdncGxvdChhZXMoeD1HZW5lcywgeT1Db21wbGV0ZW5lc3MsIGNvbG91ciA9IFN0cmFpbl9taXh0dXJlKSkgKwogIGdlb21fcG9pbnQoYWVzKHNoYXBlPURhdGEpKSArCiAgbGFicyhjb2xvdXIgPSAiU3RyYWluIG1peHR1cmU/IikgKwogIHRoZW1lX2xpZ2h0KCkgKwogICN0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkjLCAjcGxvdC5tYXJnaW4gPSBtYXJnaW4ocj0wKSkgCgpnZW5lc3ZzbWVhbmNvdmVyYWdlU3RyYWluIDwtIERhdGFHZW5lc1N0YXRzICU+JQogIGdncGxvdChhZXMoeD1HZW5lcywgeT0gTWVhbl9jb3ZlcmFnZSwgY29sb3VyID0gU3RyYWluX21peHR1cmUpKSArCiAgZ2VvbV9wb2ludChhZXMoc2hhcGU9RGF0YSkpICsKICB5bGFiKCJNZWFuIENvdmVyYWdlIikgKwogIGxhYnMoY29sb3VyID0gIlN0cmFpbiBtaXh0dXJlPyIpICsKICB0aGVtZV9saWdodCgpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkKCmdlbmVzdnNkYXRpbmdfY29tcGxldGVuZXNzIDwtIERhdGFHZW5lc1N0YXRzICU+JQogIGdncGxvdChhZXMoeD1HZW5lcywgeT1Db21wbGV0ZW5lc3MsIGNvbG91ciA9IERhdGluZykpICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZT1EYXRhKSkgKwogIHNjYWxlX2NvbG91cl92aXJpZGlzX2MoKSArCiAgdGhlbWVfbGlnaHQoKQogIApnZW5lc3ZzZGF0aW5nX21lYW5jb3YgPC0gRGF0YUdlbmVzU3RhdHMgJT4lCiAgZ2dwbG90KGFlcyh4PUdlbmVzLCB5PU1lYW5fY292ZXJhZ2UsIGNvbG91ciA9IERhdGluZykpICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZT1EYXRhKSkgKwogIHNjYWxlX2NvbG91cl92aXJpZGlzX2MoKSArCiAgdGhlbWVfbGlnaHQoKQoKCmxlZ2VuZF8xIDwtIGdldF9sZWdlbmQoZ2VuZXN2c2NvbXBsZXRlbmVzcykKCmxlZ2VuZF8yIDwtIGdldF9sZWdlbmQoZ2VuZXN2c2NvbXBsZXRlbmVzc1N0cmFpbikKIApsZWdlbmRfMyA8LSBnZXRfbGVnZW5kKGdlbmVzdnNkYXRpbmdfY29tcGxldGVuZXNzKQoKbGVnZW5kcyA8LSBnZ2FycmFuZ2UobGVnZW5kXzEsIGxlZ2VuZF8yLCBsZWdlbmRfMywgbnJvdyA9IDMpCgoKcm1fbGVnZW5kIDwtIGZ1bmN0aW9uKHApe3AgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpfQpwbG90cyA8LSBnZ2FycmFuZ2Uocm1fbGVnZW5kKGdlbmVzdnNjb21wbGV0ZW5lc3MpLAogICAgICAgICAgICAgICAgICAgcm1fbGVnZW5kKGdlbmVzdnNtZWFuY292ZXJhZ2UpLAogICAgICAgICAgICAgICAgICAgcm1fbGVnZW5kKGdlbmVzdnNjb21wbGV0ZW5lc3NTdHJhaW4pLAogICAgICAgICAgICAgICAgICAgcm1fbGVnZW5kKGdlbmVzdnNtZWFuY292ZXJhZ2VTdHJhaW4pLAogICAgICAgICAgICAgICAgICAgcm1fbGVnZW5kKGdlbmVzdnNkYXRpbmdfY29tcGxldGVuZXNzKSwKICAgICAgICAgICAgICAgICAgIHJtX2xlZ2VuZChnZW5lc3ZzZGF0aW5nX21lYW5jb3YpLAogICAgICAgICAgICAgICAgICAgIG5yb3cgPSAzLCBuY29sID0gMiwgbGFiZWxzID0gYygiQSIsICJCIiwiQyIsIkQiLCAiRSIsIkYiKSwgYWxpZ24gPSAiaHYiKQpnZ2FycmFuZ2UocGxvdHMsIGxlZ2VuZHMsIHdpZHRocyA9IGMoMC43NSwwLjI1KSkKZ2dhcnJhbmdlKHBsb3RzLCBsZWdlbmRzLCB3aWR0aHMgPSBjKDAuODUsMC4xNSkpCgpnZ3NhdmUoIi4uL0ZpZ3VyZXMvU3VwcGxlbWV0YXJ5X0ZpZ3VyZV80X2dlbmVDb3VudHNfYW5jaWVudC5wZGYiLGRldmljZSA9ICJwZGYiLCB1bml0cyA9ICJjbSIsIGhlaWdodCA9IDI1LCB3aWR0aCA9IDIzKQpgYGAKIyNCYXJwbG90IGNvcmUgdnMgYWNjZXNzb3J5IGdlbmVzCmBgYHtyfQpnZW5lQ291bnRTcGVjaWVzXzkwY29tcGxldGUgJT4lCiAgbXV0YXRlKEdlbmVUeXBlID0gaWZlbHNlKEdlbmVUeXBlID09ICJDb3JlIGdlbmVzIiwgIkNvcmUiLCAiQWNjZXNzb3J5IikpICU+JQogIGdyb3VwX2J5KEFnZSxHZW5lVHlwZSkgJT4lCiAgc3VtbWFyaXNlKEdlbmVUb3RhbCA9IG4oKSkgJT4lCmdncGxvdChhZXMoeD1BZ2UsIHk9R2VuZVRvdGFsLCBmaWxsID0gR2VuZVR5cGUpKSArCiAgZ2VvbV9iYXIocG9zaXRpb249ICJmaWxsIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjYjVlNmU2ZmYiLCIjODM2MmI3ZmYiKSkgKwogIGxhYnMoZmlsbCA9ICJHZW5lIFR5cGUiLCB4ID0gIiIsIHkgPSAiUHJvcG9ydGlvbiBvZiBwYW5nZW5vbWUiKSArCiAgdGhlbWVfbGlnaHQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJyaWdodCIpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscz0gYygiQW5jaWVudCIgPSAiQW5jaWVudFxuKG49NCw1ODApIiwgIk1vZGVybiIgPSAiTW9kZXJuXG4obj05LDYzNikiKSkKCmdnc2F2ZSgiLi4vRmlndXJlcy9QYW5lbERfbm9ybWFsaXNlZF9GaWd1cmU0X0NvcmV2c0FjY2Vzc29yeV9hbmNpZW50VlNtb2Rlcm4ucGRmIiwgZGV2aWNlID0gInBkZiIsIHVuaXRzID0gImNtIiwgaGVpZ2h0ID0gMTcsIHdpZHRoID0gMTUpCgpnZW5lQ291bnRTcGVjaWVzXzkwY29tcGxldGUgJT4lCiAgbXV0YXRlKEdlbmVUeXBlID0gaWZlbHNlKEdlbmVUeXBlID09ICJDb3JlIGdlbmVzIiwgIkNvcmUiLCAiQWNjZXNzb3J5IikpICU+JQogIGdyb3VwX2J5KEFnZSxHZW5lVHlwZSkgJT4lCiAgc3VtbWFyaXNlKEdlbmVUb3RhbCA9IG4oKSkgJT4lCmdncGxvdChhZXMoeD1BZ2UsIHk9R2VuZVRvdGFsLCBmaWxsID0gR2VuZVR5cGUpKSArCiAgZ2VvbV9iYXIocG9zaXRpb249ICJzdGFjayIsIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI2I1ZTZlNmZmIiwiIzgzNjJiN2ZmIikpICsKICBsYWJzKGZpbGwgPSAiR2VuZSBUeXBlIiwgeCA9ICIiLCB5ID0gIlByb3BvcnRpb24gb2YgcGFuZ2Vub21lIikgKwogIHRoZW1lX2xpZ2h0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0icmlnaHQiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9IGMoIkFuY2llbnQiID0gIkFuY2llbnRcbihuPTMxKSIsICJNb2Rlcm4iID0gIk1vZGVyblxuKG49NDU2KSIpKQoKZ2dzYXZlKCIuLi9GaWd1cmVzL1BhbmVsRF9yYXdfRmlndXJlNF9Db3JldnNBY2Nlc3NvcnlfYW5jaWVudFZTbW9kZXJuLnBkZiIsIGRldmljZSA9ICJwZGYiLCB1bml0cyA9ICJjbSIsIGhlaWdodCA9IDE3LCB3aWR0aCA9IDE1KQoKZ2VuZUNvdW50U3BlY2llc185MGNvbXBsZXRlICU+JQogIGZpbHRlcihBZ2UgPT0gIkFuY2llbnQiICYgR2VuZVR5cGUgPT0gIkNvcmUgZ2VuZXMiKSAlPiUKICBmaWx0ZXIoR2VuZSAlaW4lIGNvcmVHZW5lc0FsbCRHZW5lKSAlPiUKICBucm93KCkKCmdlbmVDb3VudFNwZWNpZXNfOTBjb21wbGV0ZSAlPiUKICBmaWx0ZXIoR2VuZSAlaW4lIGNvcmVHZW5lc0FsbCRHZW5lKSAlPiUKICBmaWx0ZXIoQWdlID09ICJBbmNpZW50IikgJT4lCiAgZ3JvdXBfYnkoR2VuZVR5cGUpICU+JQogIHN1bW1hcmlzZShUb3RhbCA9IG4oKSkKCm5vbkNvcmVBbmNpZW50X2NvcmVBbGwgPC0gZ2VuZUNvdW50U3BlY2llc185MGNvbXBsZXRlICU+JQogIGZpbHRlcihHZW5lICVpbiUgY29yZUdlbmVzQWxsJEdlbmUpICU+JQogIGZpbHRlcihBZ2UgPT0gIkFuY2llbnQiICYgR2VuZVR5cGUgIT0gIkNvcmUgZ2VuZXMiKSAlPiUKICBtdXRhdGUoUGVyY2VudGFnZSA9IFRvdGFsLzMxKjEwMCkKCm1lYW4obm9uQ29yZUFuY2llbnRfY29yZUFsbCRQZXJjZW50YWdlKQpzZChub25Db3JlQW5jaWVudF9jb3JlQWxsJFBlcmNlbnRhZ2UpCiAgCmBgYAojI0JveCBwbG90cyBudW1iZXIgZ2VuZXMKYGBge3J9Cgptb2Rlcm5fYW5jaWVudDkwY29tcGxldGVuZXMgPC0gbXV0YW5zX21ldGFkYXRhICU+JSAKICBmaWx0ZXIoQWdlID09ICJNb2Rlcm4iIHwgQ29tcGxldGVuZXNzID4gOTApCgojQm94cGxvdCB3aXRob3V0IHN0YXRzCmdlbmVHZW5vbWUgJT4lCiAgbXV0YXRlKFR5cGUgPSAiQXNzZW1ibHkiKSAlPiUgCiAgcmJpbmQoZ2VuZUNvdW50U3RyYWluQXNzZW1ibGVkICU+JSAKICAgICAgICAgIHNlbGVjdChTdHJhaW4sZ2VuZUNvdW50LCBUeXBlKSAlPiUgCiAgICAgICAgICByZW5hbWUoR2Vub21lID0gU3RyYWluLCBHZW5lcyA9IGdlbmVDb3VudCkpICU+JSAKICByYmluZChnZW5lQ291bnRNYXBwaW5nQXNzZW1ibGVkICU+JSAKICAgICAgICAgIGZpbHRlcihUeXBlID09ICJNYXBwaW5nIikgJT4lIAogICAgICAgICAgc2VsZWN0KFN0cmFpbiwgZ2VuZUNvdW50LCBUeXBlKSAlPiUgCiAgICAgICAgICByZW5hbWUoR2Vub21lID0gU3RyYWluLCBHZW5lcyA9IGdlbmVDb3VudCkpICU+JQogIGxlZnRfam9pbihtdXRhbnNfbWV0YWRhdGEsIGJ5ID0gYygiR2Vub21lIiA9ICJBc3NlbWJseSIpKSAlPiUKICBtdXRhdGUoQWdlID0gaWZlbHNlKGlzLm5hKEFnZSksICJBbmNpZW50IiwgQWdlKSkgJT4lCiAgZ2dwbG90KGFlcyh4PWZjdF9pbmZyZXEoQWdlKSwgeT1HZW5lcywgY29sb3VyID0gVHlwZSkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5jb2xvdXI9InJlZCIsCiAgICAgICAgICAgICAgICBvdXRsaWVyLnNpemU9MSkgKwogIHN0YXRfY29tcGFyZV9tZWFucyhjb21wYXJpc29ucyA9KQogIGxhYnMoY29sb3IgPSAiQWdlIiwgeCA9ICJBZ2UiLCB5ID0gIlRvdGFsIGdlbmUgY291bnQvZ2Vub21lIikgKwogIHRoZW1lX2xpZ2h0KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LGhqdXN0PTEpLCAKICAgICAgICBsZWdlbmQucG9zaXRpb249InJpZ2h0IikKICAjQ29tcGxleCBib3hwbG90IHdpdGggc3RhdHMKICBnZW5lR2Vub21lICU+JQogIG11dGF0ZShUeXBlID0gIiIpICU+JSAKICByYmluZChnZW5lQ291bnRTdHJhaW5Bc3NlbWJsZWQgJT4lIAogICAgICAgICAgc2VsZWN0KFN0cmFpbixnZW5lQ291bnQsIFR5cGUpICU+JSAKICAgICAgICAgIHJlbmFtZShHZW5vbWUgPSBTdHJhaW4sIEdlbmVzID0gZ2VuZUNvdW50KSkgJT4lIAogIHJiaW5kKGdlbmVDb3VudE1hcHBpbmdBc3NlbWJsZWQgJT4lIAogICAgICAgICAgZmlsdGVyKFR5cGUgPT0gIkFuY2llbnQgTWFwcGluZyIpICU+JSAKICAgICAgICAgIHNlbGVjdChTdHJhaW4sIGdlbmVDb3VudCwgVHlwZSkgJT4lIAogICAgICAgICAgcmVuYW1lKEdlbm9tZSA9IFN0cmFpbiwgR2VuZXMgPSBnZW5lQ291bnQpKSAlPiUKICBsZWZ0X2pvaW4obXV0YW5zX21ldGFkYXRhLCBieSA9IGMoIkdlbm9tZSIgPSAiQXNzZW1ibHkiKSkgJT4lCiAgICBtdXRhdGUoVHlwZSA9IGNhc2Vfd2hlbigKICAgICAgQWdlID09ICJNb2Rlcm4iIH4gIkFzc2VtYmx5IG1vZGVybiIsCiAgICAgIEFnZSA9PSAiQW5jaWVudCIgJiBUeXBlID09ICIiIH4gIkFzc2VtYmx5IGFuY2llbnQiLAogICAgICAuZGVmYXVsdCA9IFR5cGUKICAgICkpICU+JQogIGdnc3RhdHNwbG90OjpnZ2JldHdlZW5zdGF0cyh4ID0gVHlwZSwgeSA9IEdlbmVzLCB0eXBlID0gInIiKQogCiAgI0JveCBwbG90IHdpdGggc3RhdHMsIHdpdGggYW5jaWVudCA+OTAlIGNvbXBsZXRlIAogIGdlbmVHZW5vbWUgJT4lCiAgICBtdXRhdGUoVHlwZSA9ICIiKSAlPiUgCiAgICByYmluZChnZW5lQ291bnRTdHJhaW5Bc3NlbWJsZWQgJT4lIAogICAgICAgICAgICAgIHNlbGVjdChTdHJhaW4sZ2VuZUNvdW50LCBUeXBlKSAlPiUgCiAgICAgICAgICAgICAgcmVuYW1lKEdlbm9tZSA9IFN0cmFpbiwgR2VuZXMgPSBnZW5lQ291bnQpKSAlPiUgCiAgICByYmluZChnZW5lQ291bnRNYXBwaW5nQXNzZW1ibGVkICU+JSAKICAgICAgICAgICAgICBmaWx0ZXIoVHlwZSA9PSAiQW5jaWVudCBNYXBwaW5nIikgJT4lIAogICAgICAgICAgICAgIHNlbGVjdChTdHJhaW4sIGdlbmVDb3VudCwgVHlwZSkgJT4lIAogICAgICAgICAgICAgIHJlbmFtZShHZW5vbWUgPSBTdHJhaW4sIEdlbmVzID0gZ2VuZUNvdW50KSkgJT4lCiAgICBsZWZ0X2pvaW4obXV0YW5zX21ldGFkYXRhLCBieSA9IGMoIkdlbm9tZSIgPSAiQXNzZW1ibHkiKSkgJT4lCiAgICBtdXRhdGUoVHlwZSA9IGNhc2Vfd2hlbigKICAgICAgICBBZ2UgPT0gIk1vZGVybiIgfiAiQXNzZW1ibHkgbW9kZXJuIiwKICAgICAgICBBZ2UgPT0gIkFuY2llbnQiICYgVHlwZSA9PSAiIiB+ICJBc3NlbWJseSBhbmNpZW50IiwKICAgICAgICAuZGVmYXVsdCA9IFR5cGUKICAgICkpICU+JSAKICAgIGZpbHRlcihHZW5vbWUgJWluJSBtb2Rlcm5fYW5jaWVudDkwY29tcGxldGVuZXMkQXNzZW1ibHkgfCBHZW5vbWUgJWluJSBtb2Rlcm5fYW5jaWVudDkwY29tcGxldGVuZXMkU3RyYWluIHwgZ3JlcGwoIlBBTjAiLEdlbm9tZSkpICU+JQogICAgZ2dzdGF0c3Bsb3Q6OmdnYmV0d2VlbnN0YXRzKHggPSBUeXBlLCB5ID0gR2VuZXMsIHR5cGUgPSAiciIpCgogIGdnc2F2ZSgiLi4vRmlndXJlcy9TdXBwbGVtZW50YXJ5X2ZpZ3VyZV8zX2dlbm9tZXNpemVfY29tcGFyaXNvbi5wZGYiLCBkZXZpY2UgPSAicGRmIiwgdW5pdHMgPSAiY20iLCBoZWlnaHQgPSAxNSwgd2lkdGggPSAyMykKYGBgCiMjR2VuZXMgZGlmZmVyaW5nIGJldHdlZW4gYXNzZW1ibHkgYW5kIG1hcHBpbmcKYGBge3J9CmRpZmZfZ2VuZXNfYXNzZW1ibHlfbWFwcGluZyA8LSBQQV9tYXRyaXhfb25seV9hbmNpZW50ICU+JQogIGZpbHRlcihBc3NlbWJseV9uYW1lICE9ICIiKSAlPiUKICBncm91cF9ieShHZW5lLEFzc2VtYmx5X25hbWUpICU+JQogIHN1bW1hcmlzZSh0b3RhbCA9IHN1bShDb25kaXRpb24pKSAlPiUKICBncm91cF9ieShHZW5lLCB0b3RhbCkgJT4lCiAgc3VtbWFyaXNlKGNvbmNvcmRhbmNlID0gbigpKSAlPiUKICBzcHJlYWQodG90YWwsIGNvbmNvcmRhbmNlKSAlPiUKICBmaWx0ZXIoIWlzLm5hKGAxYCkpICU+JQogIG11dGF0ZShQcm9wb3J0aW9uX2NvbmNvcmRhbmNlID0gYDJgLyhgMWArYDJgKSkgJT4lCiAgbGVmdF9qb2luKGdlbmVDb3VudCAlPiUgc2VsZWN0KEdlbmUsIEdlbmVUeXBlKSkKCmdlbmVGb3VuZDFtZXRob2RHZW5vbWUgPC0gZGlmZl9nZW5lc19hc3NlbWJseV9tYXBwaW5nICU+JSAKICBmaWx0ZXIoaXMubmEoUHJvcG9ydGlvbl9jb25jb3JkYW5jZSkpICU+JSAKICBsZWZ0X2pvaW4oUEFfbWF0cml4X29ubHlfYW5jaWVudCkgJT4lIAogIGZpbHRlcihBc3NlbWJseV9uYW1lICE9ICIiKSAlPiUgCiAgZ3JvdXBfYnkoR2VuZSxUeXBlKSAlPiUgCiAgc3VtbWFyaXNlKFRvdGFsID0gbigpKSAlPiUgCiAgbGVmdF9qb2luKGdlbmVDb3VudCAlPiUgCiAgICAgICAgICAgICAgc2VsZWN0KEdlbmUsIEdlbmVUeXBlKSkKCmdlbmVzRm91bmRPbmx5MW1ldGhvZCA8LSBnZW5lRm91bmQxbWV0aG9kR2Vub21lICU+JSAKICBncm91cF9ieShHZW5lKSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsID0gbigpKSAlPiUgCiAgZmlsdGVyKHRvdGFsID09IDEpICU+JSAKICBzZWxlY3QoR2VuZSkKCiNnZW5lRm91bmQxbWV0aG9kR2Vub21lICU+JSAKIyAgZmlsdGVyKEdlbmUgJWluJSBnZW5lc0ZvdW5kT25seTFtZXRob2QkR2VuZSkgJT4lIAojICBncm91cF9ieShUeXBlLCBHZW5lVHlwZSkgJT4lCiMgIHN1bW1hcmlzZShnZW5lQ291bnQgPSBuKCkpICsKIyAgZ2dwbG90KGFlcyh4PUdlbmVUeXBlLCB5PUdlbmVUb3RhbCwgZmlsbCA9IEFnZSkpICsKIyAgZ2VvbV9iYXIocG9zaXRpb249ICJkb2RnZSIsIHN0YXQ9ImlkZW50aXR5IikgKwojICBsYWJzKGNvbG9yID0gIkFnZSIsIHggPSAiQWdlIiwgeSA9ICJUb3RhbCBnZW5lIGNvdW50L2dlbm9tZSIpICsKIyAgdGhlbWVfYncoKSArCiMgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LGhqdXN0PTEpLCAKIyAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJyaWdodCIpCgphbmNpZW50X2JyZWFkdGhfZGVwdGhfY292ICU+JSBmaWx0ZXIoR2VuZSAlaW4lIGdlbmVzRm91bmRPbmx5MW1ldGhvZCRHZW5lKSAlPiUgCiAgbGVmdF9qb2luKGdlbmVDb3VudCAlPiUgCiAgICAgICAgICAgICAgc2VsZWN0KEdlbmUsIEdlbmVUeXBlKSkgJT4lCiAgZmlsdGVyKEdlbmVUeXBlID09ICJDb3JlIGdlbmVzIikKCmdlbmVGb3VuZDFtZXRob2RHZW5vbWUgJT4lIGZpbHRlcihUeXBlPT0iQW5jaWVudCBNYXBwaW5nIikgJT4lIGdyb3VwX2J5KEdlbmVUeXBlKSAlPiUgc3VtbWFyaXNlKFRvdGFsPW4oKSkKYGBg